#include "BlackDeath.Core.h"

namespace BlackDeath
{
	namespace Core
	{
		#pragma region Constructors and Destructor
		CGameComponentManager::CGameComponentManager(BlackDeath::Core::CGame* game)
		{
			this->m_pGame = game;
			this->m_eState = ComponentManagerState::Created;
		}
		#pragma endregion

		#pragma region Properties
		int CGameComponentManager::Get_Count()
		{
			return this->m_lComponents.size() + this->m_lDrawableComponents.size();
		}

		std::vector<BlackDeath::Core::CGameComponent*>* CGameComponentManager::Get_GameComponents()
		{
			return &this->m_lComponents;
		}
		
		std::vector<BlackDeath::Core::CDrawableGameComponent*>* CGameComponentManager::Get_DrawableGameComponents()
		{
			return &this->m_lDrawableComponents;
		}
		#pragma endregion

		#pragma region Options
		void CGameComponentManager::Clear()
		{
			this->m_lComponents.clear();			 
			this->m_lDrawableComponents.clear();
		}

		void CGameComponentManager::Add(BlackDeath::Core::CGameComponent* component)
		{
			 
			BlackDeath::Core::CDrawableGameComponent* drawableComponent = dynamic_cast<BlackDeath::Core::CDrawableGameComponent*>(component);
			if(drawableComponent != NULL)
				this->m_lDrawableComponents.push_back(drawableComponent);
			else			
				this->m_lComponents.push_back(component);
			
			if(this->m_eState >= ComponentManagerState::Initialized)
				component->Initialize();
			
			if(drawableComponent != NULL && this->m_eState >= ComponentManagerState::LoadedContent)
				drawableComponent->LoadContent();
		}

		void CGameComponentManager::Remove(BlackDeath::Core::CGameComponent* component)
		{			
			BlackDeath::Core::CDrawableGameComponent* drawableComponent = dynamic_cast<BlackDeath::Core::CDrawableGameComponent*>(component);

			if(drawableComponent != NULL)
			{
				std::vector<CDrawableGameComponent*>::iterator it;
				for(it = this->m_lDrawableComponents.begin(); it != this->m_lDrawableComponents.end(); it++)
				{
					if((*it) == drawableComponent)
					{
						this->m_lDrawableComponents.erase(it);
						return;
					}
				}
			}
			else
			{			
				std::vector<CGameComponent*>::iterator it;

				for(it = this->m_lComponents.begin(); it != this->m_lComponents.end(); it++)
				{
					if((*it) == component)
					{
						this->m_lComponents.erase(it);
						return;
					}
				}
			}			
		}
		#pragma endregion

		#pragma region Methods
		void CGameComponentManager::Initialize()
		{
			this->m_eState = ComponentManagerState::Initialized;

			int size = this->m_lComponents.size();
			for(int i = 0; i < size; i++)
				this->m_lComponents[i]->Initialize();
			
			size = this->m_lDrawableComponents.size();
			for(int i = 0; i < size; i++)
				this->m_lDrawableComponents[i]->Initialize();
		}

		void CGameComponentManager::LoadContent()
		{
			this->m_eState = ComponentManagerState::LoadedContent;			
			 
			int size = this->m_lDrawableComponents.size();
			for(int i = 0; i < size; i++)
				this->m_lDrawableComponents[i]->LoadContent();
		}

		void CGameComponentManager::Update(BlackDeath::Core::CGameTime* gameTime)
		{
			this->m_eState = ComponentManagerState::Updated;

			//size may change if a unit calls Remove during their Update
			for(int i = 0; i < this->m_lComponents.size(); i++)
				this->m_lComponents[i]->InternalUpdate(gameTime);
			 
			for(int i = 0; i < this->m_lDrawableComponents.size(); i++)
				this->m_lDrawableComponents[i]->InternalUpdate(gameTime);				
		}

		void CGameComponentManager::Draw(BlackDeath::Core::CGameTime* gameTime)
		{
			this->m_eState = ComponentManagerState::Drawn;	
			
			int size = this->m_lDrawableComponents.size();
			for(int i = 0; i < size; i++)
				this->m_lDrawableComponents[i]->InternalDraw(gameTime);
		}
		#pragma endregion

		#pragma region Operator Overriden Methods
		BlackDeath::Core::CGameComponent* CGameComponentManager::operator[] (const int index)
		{
			int size = this->m_lComponents.size();			
			if(index >= size)
				return this->m_lDrawableComponents[index - size];				
			return this->m_lComponents[index];
		}
		#pragma endregion
	}
}